"""
Docker操作封装服务 - Docker命令的底层封装
"""

import subprocess
import json
import logging
from typing import Dict, List, Optional, Any

from ..core.types import OperationResult, ImageInfo, ContainerInfo, ContainerStatus


logger = logging.getLogger(__name__)


class DockerService:
    """Docker操作的底层封装服务"""
    
    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)
    
    def pull_image(self, image_url: str) -> OperationResult:
        """
        拉取Docker镜像
        
        Args:
            image_url: 镜像URL
            
        Returns:
            OperationResult: 操作结果
        """
        try:
            self.logger.info(f"开始拉取镜像: {image_url}")
            
            cmd = ['docker', 'pull', image_url]
            result = subprocess.run(
                cmd, 
                capture_output=True, 
                text=True, 
                timeout=600  # 10分钟超时
            )
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"镜像拉取成功: {image_url}",
                    details={
                        "image_url": image_url,
                        "stdout": result.stdout,
                        "stderr": result.stderr
                    }
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"镜像拉取失败: {result.stderr}",
                    error=result.stderr,
                    details={"image_url": image_url}
                )
                
        except subprocess.TimeoutExpired:
            return OperationResult(
                success=False,
                message=f"镜像拉取超时: {image_url}",
                error="Pull operation timed out",
                details={"image_url": image_url}
            )
        except Exception as e:
            self.logger.error(f"拉取镜像失败: {e}")
            return OperationResult(
                success=False,
                message=f"拉取镜像失败: {str(e)}",
                error=str(e),
                details={"image_url": image_url}
            )
    
    def get_image_info(self, image_url: str) -> Optional[ImageInfo]:
        """
        获取镜像信息
        
        Args:
            image_url: 镜像URL
            
        Returns:
            Optional[ImageInfo]: 镜像信息
        """
        try:
            cmd = ['docker', 'images', image_url, '--format', 'json']
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            
            if result.returncode == 0 and result.stdout.strip():
                # Docker可能返回多行JSON，取第一行
                first_line = result.stdout.strip().split('\n')[0]
                image_data = json.loads(first_line)
                
                return ImageInfo(
                    id=image_data.get('ID', ''),
                    repository=image_data.get('Repository', ''),
                    tag=image_data.get('Tag', ''),
                    created_at=image_data.get('CreatedAt', ''),
                    size=image_data.get('Size', ''),
                    digest=image_data.get('Digest')
                )
        except Exception as e:
            self.logger.debug(f"获取镜像信息失败: {e}")
            
        return None
    
    def get_container_info(self, container_name: str) -> Optional[ContainerInfo]:
        """
        获取容器信息
        
        Args:
            container_name: 容器名称
            
        Returns:
            Optional[ContainerInfo]: 容器信息
        """
        try:
            cmd = ['docker', 'ps', '-a', '--filter', f'name=^{container_name}$', '--format', 'json']
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            
            if result.returncode == 0 and result.stdout.strip():
                first_line = result.stdout.strip().split('\n')[0]
                container_data = json.loads(first_line)
                
                # 解析容器状态
                status_str = container_data.get('State', 'unknown').lower()
                if 'running' in status_str:
                    status = ContainerStatus.RUNNING
                elif 'exited' in status_str or 'stopped' in status_str:
                    status = ContainerStatus.STOPPED
                else:
                    status = ContainerStatus.UNKNOWN
                
                return ContainerInfo(
                    id=container_data.get('ID', ''),
                    name=container_data.get('Names', ''),
                    image=container_data.get('Image', ''),
                    status=status,
                    created_at=container_data.get('CreatedAt', ''),
                    ports=self._parse_ports(container_data.get('Ports', ''))
                )
        except Exception as e:
            self.logger.debug(f"获取容器信息失败: {e}")
            
        return None
    
    def list_running_containers(self) -> List[ContainerInfo]:
        """获取所有运行中的容器列表"""
        try:
            cmd = ['docker', 'ps', '--format', 'json']
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            
            containers = []
            if result.returncode == 0 and result.stdout.strip():
                for line in result.stdout.strip().split('\n'):
                    try:
                        container_data = json.loads(line)
                        containers.append(ContainerInfo(
                            id=container_data.get('ID', ''),
                            name=container_data.get('Names', ''),
                            image=container_data.get('Image', ''),
                            status=ContainerStatus.RUNNING,
                            created_at=container_data.get('CreatedAt', ''),
                            ports=self._parse_ports(container_data.get('Ports', ''))
                        ))
                    except Exception:
                        continue
                        
            return containers
            
        except Exception as e:
            self.logger.error(f"获取容器列表失败: {e}")
            return []
    
    def start_container(self, container_name: str) -> OperationResult:
        """启动容器"""
        try:
            cmd = ['docker', 'start', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"容器启动成功: {container_name}",
                    details={"container_name": container_name}
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"容器启动失败: {result.stderr}",
                    error=result.stderr,
                    details={"container_name": container_name}
                )
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"启动容器失败: {str(e)}",
                error=str(e)
            )
    
    def stop_container(self, container_name: str) -> OperationResult:
        """停止容器"""
        try:
            cmd = ['docker', 'stop', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"容器停止成功: {container_name}",
                    details={"container_name": container_name}
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"容器停止失败: {result.stderr}",
                    error=result.stderr,
                    details={"container_name": container_name}
                )
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"停止容器失败: {str(e)}",
                error=str(e)
            )
    
    def restart_container(self, container_name: str) -> OperationResult:
        """重启容器"""
        try:
            cmd = ['docker', 'restart', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"容器重启成功: {container_name}",
                    details={"container_name": container_name}
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"容器重启失败: {result.stderr}",
                    error=result.stderr,
                    details={"container_name": container_name}
                )
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"重启容器失败: {str(e)}",
                error=str(e)
            )
    
    def remove_container(self, container_name: str, force: bool = False) -> OperationResult:
        """删除容器"""
        try:
            cmd = ['docker', 'rm']
            if force:
                cmd.append('-f')
            cmd.append(container_name)
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"容器删除成功: {container_name}",
                    details={"container_name": container_name}
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"容器删除失败: {result.stderr}",
                    error=result.stderr,
                    details={"container_name": container_name}
                )
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"删除容器失败: {str(e)}",
                error=str(e)
            )
    
    def compose_up(self, compose_file: str, env_vars: Dict[str, str] = None) -> OperationResult:
        """使用docker-compose启动服务"""
        try:
            cmd = ['docker-compose', '-f', compose_file, 'up', '-d']
            
            # 设置环境变量
            env = None
            if env_vars:
                import os
                env = os.environ.copy()
                env.update(env_vars)
            
            result = subprocess.run(
                cmd, 
                capture_output=True, 
                text=True, 
                timeout=300,  # 5分钟超时
                env=env
            )
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"Docker Compose启动成功: {compose_file}",
                    details={
                        "compose_file": compose_file,
                        "env_vars": env_vars,
                        "stdout": result.stdout,
                        "stderr": result.stderr
                    }
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"Docker Compose启动失败: {result.stderr}",
                    error=result.stderr,
                    details={
                        "compose_file": compose_file,
                        "env_vars": env_vars
                    }
                )
                
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"Docker Compose操作失败: {str(e)}",
                error=str(e)
            )
    
    def compose_down(self, compose_file: str) -> OperationResult:
        """使用docker-compose停止服务"""
        try:
            cmd = ['docker-compose', '-f', compose_file, 'down']
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
            
            if result.returncode == 0:
                return OperationResult(
                    success=True,
                    message=f"Docker Compose停止成功: {compose_file}",
                    details={
                        "compose_file": compose_file,
                        "stdout": result.stdout,
                        "stderr": result.stderr
                    }
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"Docker Compose停止失败: {result.stderr}",
                    error=result.stderr,
                    details={"compose_file": compose_file}
                )
                
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"Docker Compose停止失败: {str(e)}",
                error=str(e)
            )
    
    def get_container_logs(self, container_name: str, lines: int = 100) -> OperationResult:
        """获取容器日志"""
        try:
            cmd = ['docker', 'logs', '--tail', str(lines), container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            return OperationResult(
                success=True,
                message=f"获取容器日志成功: {container_name}",
                details={
                    "container_name": container_name,
                    "logs": result.stdout,
                    "errors": result.stderr
                }
            )
            
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"获取容器日志失败: {str(e)}",
                error=str(e)
            )
    
    def inspect_container(self, container_name: str) -> OperationResult:
        """检查容器详细信息"""
        try:
            cmd = ['docker', 'inspect', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            
            if result.returncode == 0:
                inspect_data = json.loads(result.stdout)
                return OperationResult(
                    success=True,
                    message=f"容器检查成功: {container_name}",
                    details={
                        "container_name": container_name,
                        "inspect_data": inspect_data
                    }
                )
            else:
                return OperationResult(
                    success=False,
                    message=f"容器检查失败: {result.stderr}",
                    error=result.stderr
                )
                
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"检查容器失败: {str(e)}",
                error=str(e)
            )
    
    def _parse_ports(self, ports_str: str) -> Dict[str, str]:
        """解析端口映射字符串"""
        ports = {}
        if not ports_str:
            return ports
            
        try:
            # Docker端口格式: "0.0.0.0:8080->8080/tcp"
            for port_mapping in ports_str.split(', '):
                if '->' in port_mapping:
                    external, internal = port_mapping.split('->')
                    external_port = external.split(':')[-1]
                    internal_port = internal.split('/')[0]
                    ports[internal_port] = external_port
        except Exception as e:
            self.logger.debug(f"解析端口映射失败: {e}")
            
        return ports